home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Tool Chest / Text / WASTE / WASTE 1.2a2 / WEScraps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-12  |  11.1 KB  |  434 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEScraps.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Routines for Manipulating Style Scraps and Object Soups
  6.  *
  7.  *  Copyright (c) 1993-1995 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. pascal OSErr _WEPrependStyle(Handle hStyleScrap, const WERunInfo *info, long offsetDelta)
  18. {
  19.     // compare the stylistic attributes in info with the first element of the specified
  20.     // style scrap: if they differ, prepend a new element to the style scrap.
  21.     // in any case, advance all character offsets in the style scrap by offsetDelta
  22.  
  23.     TEStyleScrapPtr pScrap;
  24.     TEStyleScrapElement element;
  25.     short i;
  26.     OSErr err;
  27.  
  28.     pScrap = * (TEStyleScrapHandle) hStyleScrap;
  29.  
  30.     // compare this style info with that stored in the first element of our private style scrap
  31.     if (!_WEBlockCmp(&pScrap->scrpStyleTab[0].scrpTEAttrs, &info->runAttrs, sizeof(TERunAttributes)))
  32.     {
  33.         // insert a new style scrap element at the beginning of the style scrap
  34.         element.scrpStartChar = 0;
  35.         element.scrpTEAttrs = * (TERunAttributes *) &info->runAttrs;
  36.         
  37.         if ((err = _WEInsertBlock(hStyleScrap, &element, sizeof(element), sizeof(short))) != noErr)
  38.             return err;
  39.  
  40.         pScrap = * (TEStyleScrapHandle) hStyleScrap;
  41.  
  42.         // increment element count
  43.         pScrap->scrpNStyles++;
  44.  
  45.     } // if not _WEBlockCmp
  46.  
  47.     // update char offsets within the style scrap
  48.     for(i = pScrap->scrpNStyles - 1; i > 0; i--)
  49.         pScrap->scrpStyleTab[i].scrpStartChar += offsetDelta;
  50.  
  51.     return noErr;
  52.  
  53. } // _WEPrependStyle
  54.  
  55. pascal OSErr _WEAppendStyle(Handle hStyleScrap, const WERunInfo *info, long offset)
  56. {
  57.  
  58.     // compare the stylistic attributes in info with the last element of the specified
  59.     // style scrap: if they differ, append a new element to the style scrap.
  60.  
  61.     TEStyleScrapPtr pScrap;
  62.     TEStyleScrapElement element;
  63.     OSErr err;
  64.  
  65.     pScrap = * (TEStyleScrapHandle) hStyleScrap;
  66.     // compare this style info with that stored in the first element of our private style scrap
  67.     if (_WEBlockCmp((Ptr)&pScrap->scrpStyleTab[pScrap->scrpNStyles - 1].scrpTEAttrs,
  68.         (Ptr)&info->runAttrs, sizeof(TERunAttributes)) == false) 
  69.     {
  70.  
  71.         // create a new style scrap element
  72.         element.scrpStartChar = offset;
  73.         element.scrpTEAttrs = * (TERunAttributes *) &info->runAttrs;
  74.  
  75.         // append it at the end of the style scrap
  76.         err = PtrAndHand(&element, hStyleScrap, sizeof(element));
  77.         if ((err = MemError()) != noErr)
  78.             return err;
  79.  
  80.         // increment scrap counter
  81.         pScrap = * (TEStyleScrapHandle) hStyleScrap;
  82.         pScrap->scrpNStyles++;
  83.  
  84.     } // if not _WEBlockCmp
  85.  
  86.     // return result code
  87.     return noErr;
  88. } // _WEAppendStyle
  89.  
  90. #if WASTE_OBJECTS
  91.  
  92. pascal OSErr _WEPrependObject(Handle hSoup, const WERunInfo *info, long offsetDelta)
  93. {
  94.     // if info describes an embedded object, prepend a new object descriptor,
  95.     // complete with the associated object data, to the specified soup.
  96.     // in any case, advance all character offsets in the soup by offsetDelta
  97.  
  98.     WEObjectDescHandle hObjectDesc = info->runAttrs.runStyle.tsObject;
  99.     Handle hObjectData = NULL;
  100.     FlavorType objectType;
  101.     Boolean disposeData;
  102.     WESoupPtr pSoup;
  103.     Size soupSize, objectDataSize, extraSize;
  104.     OSErr err;
  105.  
  106.     // get size of existing soup
  107.     soupSize = GetHandleSize(hSoup);
  108.  
  109.     if (hObjectDesc != NULL) 
  110.     {
  111.         
  112.         // create a temporary handle for the streaming callback
  113.         if ((err = _WEAllocate(0, kAllocTemp, &hObjectData)) != noErr)
  114.             goto cleanup;
  115.         
  116.         // get the object type/data
  117.         if ((err = _WEStreamObject(weToSoup, &objectType, &hObjectData, &disposeData, hObjectDesc)) != noErr)
  118.             goto cleanup;
  119.  
  120.         // get size of object data
  121.         objectDataSize = GetHandleSize(hObjectData);
  122.  
  123.         // extra size to add to existing soup is descriptor size + object data size
  124.         extraSize = sizeof(WESoup) + objectDataSize;
  125.  
  126.         // resize the soup
  127.         SetHandleSize(hSoup, soupSize + extraSize);
  128.         if ((err = MemError()) != noErr)
  129.             goto cleanup;
  130.  
  131.         // move old contents forward
  132.         pSoup = * (WESoupHandle) hSoup;
  133.         BlockMoveData((Ptr) pSoup, (Ptr) pSoup + extraSize, soupSize);
  134.  
  135.         // insert the new object descriptor at the beginning
  136.         BLOCK_CLR(*pSoup);
  137.         pSoup->soupType = objectType;
  138.         pSoup->soupSize = (*hObjectDesc)->objectSize;
  139.         pSoup->soupDataSize = objectDataSize;
  140.  
  141.         //  copy the object data
  142.         BlockMoveData(*hObjectData, (Ptr) (pSoup + 1), objectDataSize);
  143.     }
  144.     else
  145.     {
  146.         pSoup = * (WESoupHandle) hSoup;
  147.         extraSize = 0;
  148.     }
  149.  
  150.     // update char offsets within the soup
  151.     while (soupSize > 0)
  152.     {
  153.         pSoup = (WESoupPtr) ((Ptr) pSoup + extraSize);
  154.         pSoup->soupOffset += offsetDelta;
  155.         extraSize = sizeof(WESoup) + pSoup->soupDataSize;
  156.         soupSize -= extraSize;
  157.     }
  158.  
  159.     err = noErr;
  160.  
  161. cleanup:
  162.     if (disposeData)
  163.         _WEForgetHandle(&hObjectData);
  164.  
  165.     return err;
  166.  
  167. } // _WEPrependObject
  168.  
  169. pascal OSErr _WEAppendObject(Handle hSoup, const WERunInfo *info, long offset)
  170. {
  171.  
  172.     // if info describes an embedded object, append a new object descriptor,
  173.     // complete with the associated object data, to the specified soup.
  174.  
  175.     WEObjectDescHandle hObjectDesc = info->runAttrs.runStyle.tsObject;
  176.     Handle hObjectData = NULL;
  177.     FlavorType objectType;
  178.     WESoup soupItem;
  179.     Boolean saveDataLock;
  180.     Boolean disposeData;
  181.     OSErr err;
  182.  
  183.     if (hObjectDesc != NULL)
  184.     {
  185.         // create a temporary handle for the streaming callback
  186.         if ((err = _WEAllocate(0, kAllocTemp, &hObjectData)) != noErr)
  187.             goto cleanup;
  188.         
  189.         // get the object type/data
  190.         if ((err = _WEStreamObject(weToSoup, &objectType, &hObjectData, &disposeData, hObjectDesc)) != noErr)
  191.             goto cleanup;
  192.  
  193.         // fill in a soup item
  194.         BLOCK_CLR(soupItem);
  195.         soupItem.soupOffset = offset;
  196.         soupItem.soupType = objectType;
  197.         soupItem.soupSize = (*hObjectDesc)->objectSize;
  198.         soupItem.soupDataSize = GetHandleSize(hObjectData);
  199.  
  200.         // append it to the soup handle
  201.         PtrAndHand(&soupItem, hSoup, sizeof(soupItem));
  202.         if ((err = MemError()) != noErr)
  203.             goto cleanup;
  204.  
  205.         // append the actual object data to the soup handle
  206.         saveDataLock = _WESetHandleLock(hObjectData, true);
  207.         PtrAndHand(*hObjectData, hSoup, soupItem.soupDataSize);
  208.         err = MemError();
  209.         _WESetHandleLock(hObjectData, saveDataLock);
  210.         if (err != noErr)
  211.             goto cleanup;
  212.     } // if object reference is not NULL
  213.  
  214.     err = noErr;
  215.  
  216. cleanup:
  217.     if (disposeData)
  218.         _WEForgetHandle(&hObjectData);
  219.  
  220.     return err;
  221.  
  222. } // _WEAppendObject
  223.  
  224. #endif
  225.  
  226. pascal OSErr WECopyRange(long rangeStart, long rangeEnd, Handle hText,
  227.                     Handle hStyles, Handle hSoup, WEHandle hWE)
  228. {
  229.  
  230.     // Make a copy of the specified range of text: store the characters in hText
  231.     // and the associated style scrap in hStyles.  The handles are resized as necessary.
  232.     // Specify NULL in hText or hStyles if you don't want the corresponding info returned.
  233.  
  234.     WEPtr pWE;
  235.     TEStyleScrapElementPtr pElement;
  236.     long rangeLength;
  237.     long firstRun, nRuns, i;
  238.     long startChar;
  239.     WERunInfo info;
  240.     Boolean saveWELock;
  241.     OSErr err;
  242.  
  243.     // lock the WE record
  244.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  245.     pWE = *hWE;
  246.  
  247.     // range-check parameters and reorder them if necessary
  248.     rangeStart = _WEPinInRange(rangeStart, 0, pWE->textLength);
  249.     rangeEnd = _WEPinInRange(rangeEnd, 0, pWE->textLength);
  250.     _WEReorder(&rangeStart, &rangeEnd);
  251.     rangeLength = rangeEnd - rangeStart;
  252.  
  253.     if (hText != NULL) 
  254.     {
  255.         // resize the given handle
  256.         SetHandleSize(hText, rangeLength);
  257.         if ((err = MemError()) != noErr) 
  258.             goto cleanup;
  259.  
  260.         // copy the text range
  261.         BlockMoveData((Ptr) *pWE->hText + rangeStart, (Ptr) *hText, rangeLength);
  262.     }
  263.  
  264.     // make the soup handle zero-length
  265.     if (hSoup != NULL)
  266.     {
  267.         SetHandleSize(hSoup, 0);
  268.         if ((err = MemError()) != noErr)
  269.             goto cleanup;
  270.     }
  271.  
  272.     if ((hStyles != NULL) || (hSoup != NULL))
  273.     {
  274.         // count how many style runs there are in the selection range
  275.         firstRun = _WEOffsetToRun(rangeStart, hWE);
  276.         nRuns = _WEOffsetToRun(rangeEnd - 1, hWE) - firstRun + 1;
  277.  
  278.         if (hStyles != NULL)
  279.         {
  280.             // resize the given style scrap handle and lock it in high heap
  281.             SetHandleSize(hStyles, (nRuns * sizeof(ScrpSTElement)) + sizeof(short));
  282.             if ((err = MemError()) != noErr)
  283.                 goto cleanup;
  284.             HLockHi(hStyles);
  285.             
  286.             // fill in the style count in the style scrap
  287.             // *** POTENTIAL PROBLEM: if nRuns > 32767, scrpNStyles will be invalid ***
  288.             WEASSERT(nRuns <= SHRT_MAX, "\pToo many styles");
  289.             (* (TEStyleScrapHandle) hStyles)->scrpNStyles = nRuns;
  290.         }
  291.         
  292.         pElement = & ((* (TEStyleScrapHandle) hStyles)->scrpStyleTab[0]);
  293.         // loop through every style run in the selection range
  294.         for ( i = 0; i < nRuns; i++ )
  295.         {
  296.             _WEGetIndStyle(firstRun + i, &info, hWE);
  297.             
  298.             // calculate the start character for this style run, relative to the beginning of the range
  299.             startChar = info.runStart - rangeStart;
  300.             if (startChar < 0)
  301.             {
  302.                 startChar = 0;
  303. #if WASTE_OBJECTS
  304.                 info.runAttrs.runStyle.tsObject = NULL;
  305. #endif
  306.             }
  307.             if (hStyles != NULL)
  308.             {
  309.                 info.runAttrs.runStyle.tsFlags = 0; // don't export internal flags
  310.                 pElement->scrpStartChar = startChar;
  311.                 pElement->scrpTEAttrs = * (TERunAttributes *) &info.runAttrs;
  312.                 pElement++;
  313.             }
  314.  
  315. #if WASTE_OBJECTS
  316.             if (hSoup != NULL)
  317.             {
  318.                 // if this style run references an embedded object, append it to the "soup"
  319.                 if (info.runAttrs.runStyle.tsObject != NULL)
  320.                 {
  321.                     if ((err = _WEAppendObject(hSoup, &info, startChar)) != noErr)
  322.                         goto cleanup;
  323.                 }
  324.             }
  325. #endif
  326.  
  327.         }
  328.     }
  329.     // clear result code
  330.     err = noErr;
  331.  
  332. cleanup:
  333.     
  334.     // unlock the style scrap handle
  335.     if (hStyles != NULL)
  336.         HUnlock(hStyles);
  337.  
  338.     // unlock the WE record
  339.     _WESetHandleLock((Handle) hWE, saveWELock);
  340.     // return result code
  341.     return err;
  342. }
  343.  
  344. pascal OSErr WECopy(WEHandle hWE)
  345. {
  346.     // Copy the selection range to the desk scrap
  347.  
  348.     WEPtr pWE;
  349.     AEDesc d[3] = { { kTypeText, NULL }, { kTypeStyles, NULL }, { kTypeSoup, NULL } };
  350.     Handle hItem;
  351.     Size itemSize;
  352.     short i, numTypes;
  353.     Boolean saveWELock;
  354.     Boolean saveDataLock;
  355.     Boolean disposeData = true;
  356.     OSErr err;
  357. #if WASTE_OBJECTS
  358.     WEObjectDescHandle hObjectDesc = NULL;
  359. #endif
  360.  
  361.     // lock the WE record
  362.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  363.     pWE = *hWE;
  364.  
  365.     // return weEmptySelectionErr if the selection range is empty
  366.     if (pWE->selStart == pWE->selEnd)
  367.     {
  368.         err = weEmptySelectionErr;
  369.         goto cleanup;
  370.     }
  371.     
  372.     // clear the desk scrap
  373.     if ((err = ZeroScrap()) != noErr)
  374.         goto cleanup;
  375.  
  376. #if WASTE_OBJECTS
  377.     numTypes = (WEGetSelectedObject(&hObjectDesc, hWE) == noErr) ? 1 : 3;
  378. #else
  379.     numTypes = 2;
  380. #endif
  381.  
  382.     // allocate some temporary handles
  383.     for ( i = 0; i < numTypes; i++ )
  384.     {
  385.         if ((err = _WEAllocate(0, kAllocTemp, &d[i].dataHandle)) != noErr)
  386.             goto cleanup;
  387.     }
  388.  
  389. #if WASTE_OBJECTS
  390.     if (hObjectDesc != NULL)
  391.     {
  392.         if ((err = _WEStreamObject(weToScrap, &d[0].descriptorType, &d[0].dataHandle,
  393.                     &disposeData, hObjectDesc)) != noErr)
  394.             goto cleanup;
  395.     }
  396.     else
  397. #endif
  398.     {
  399.         // make a copy of the selection text and styles and create an object "soup"
  400.         if ((err = WECopyRange(pWE->selStart, pWE->selEnd,
  401.             d[0].dataHandle, d[1].dataHandle, d[2].dataHandle, hWE)) != noErr)
  402.             goto cleanup;
  403.     }
  404.     
  405.     // copy the items to the desk scrap
  406.     for ( i = 0; i < numTypes; i++ )
  407.     {
  408.         hItem = d[i].dataHandle;
  409.         itemSize = GetHandleSize(hItem);
  410.         if (itemSize > 0)
  411.         {
  412.             saveDataLock = _WESetHandleLock(hItem, true);
  413.             err = PutScrap(itemSize, d[i].descriptorType, *hItem);
  414.             _WESetHandleLock(hItem, saveDataLock);
  415.             if (err != noErr)
  416.                 goto cleanup;
  417.         }
  418.     }
  419.  
  420.     // clear result code
  421.     err = noErr;
  422.  
  423. cleanup:
  424.     // clean up
  425.     if (disposeData)
  426.     {
  427.         _WEForgetHandle(&d[0].dataHandle);
  428.         _WEForgetHandle(&d[1].dataHandle);
  429.         _WEForgetHandle(&d[2].dataHandle);
  430.     }
  431.     _WESetHandleLock((Handle) hWE, saveWELock);
  432.     return err;
  433. }
  434.